/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using DaveSexton.Controls;
using System.Xml.XPath;

namespace DaveSexton.DocProject.Sandcastle.TopicManagement
{
	internal sealed class TopicXmlTreeViewDataManager : XmlTreeViewDataManager
	{
		#region Public Properties
		public override bool BindToDataSourceChildren
		{
			get
			{
				return true;
			}
		}
		#endregion

		#region Private / Protected
		private bool checkingSiblingNodes;
		private readonly ConceptualTopicFileManager conceptualTopicManager;
		private readonly TopicManager topicManager;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="TopicXmlTreeViewDataManager" /> class.
		/// </summary>
		internal TopicXmlTreeViewDataManager(ConceptualTopicFileManager conceptualTopicManager, TopicManager topicManager)
		{
			if (conceptualTopicManager == null)
				throw new ArgumentNullException("conceptualTopicManager");

			if (topicManager == null)
				throw new ArgumentNullException("topicManager");

			this.conceptualTopicManager = conceptualTopicManager;
			this.topicManager = topicManager;
		}
		#endregion

		#region Methods
		public static TopicType GetTopicType(XmlTreeNode node)
		{
			return ((TopicNode) node).Topic.TopicType;
		}

		public override bool CanDeleteElement(XmlTreeNode node, IXPathNavigable element)
		{
			TopicType type = GetTopicType(node);

			return type == TopicType.Conceptual || type == TopicType.Container || type == TopicType.Html;
		}

		public override bool ShouldDeleteRecursive(XmlTreeNode node, IXPathNavigable element)
		{
			return GetTopicType(node) == TopicType.Container;
		}

		public override bool DeleteElement(XmlTreeNode node, IXPathNavigable element)
		{
			if (element == null)
				throw new ArgumentNullException("element");

			// NOTE: Always delete recursive since the tree view will automatically move child elements to the 
			// parent before this method is called when the overriden ShouldDeleteRecursive method returns false.
			conceptualTopicManager.DeleteTopicsRecursive(element);

			if (GetTopicType(node) == TopicType.Container)
			{
				XPathNavigator root = conceptualTopicManager.Topics.ApiRoot.CreateNavigator();
				XPathNavigator navigator = element.CreateNavigator();

				if (navigator.IsDescendant(root))
				{
					navigator.ReplaceSelf(root);
					root.DeleteSelf();

					OnElementChanged(new ElementChangedEventArgs(element, ElementChangeType.Deleted));

					node.DataSource = navigator;
					return false;
				}
			}

			return base.DeleteElement(node, element);
		}

		public override bool CanMoveElement(XmlTreeNode node, IXPathNavigable element)
		{
			return GetTopicType(node) != TopicType.General;
		}

		public override bool CanContainElement(XmlTreeNode node, IXPathNavigable element, XmlTreeNode parent, IXPathNavigable parentElement)
		{
			TopicType type = GetTopicType(node);

			if (type == TopicType.Conceptual || type == TopicType.Container || type == TopicType.Html || type == TopicType.Project)
			{
				if (parent == null)
					// NOTE: a null parent represents the tree's root
					return true;
				else
				{
					TopicType parentType = GetTopicType(parent);

					return parentType == TopicType.Conceptual || parentType == TopicType.Container || parentType == TopicType.Html;
				}
			}

			return false;
		}

		public override bool CanEditElement(XmlTreeNode node, IXPathNavigable element)
		{
			TopicType type = GetTopicType(node);

			return type == TopicType.Conceptual || type == TopicType.Container;		// || type == TopicType.Project;
		}

		public override void SetElementLabel(XmlTreeNode node, IXPathNavigable element, string label)
		{
			TopicType type = GetTopicType(node);

			if (type == TopicType.Conceptual || type == TopicType.Container || type == TopicType.Html)
			{
				topicManager.GetMetadata(element).TocTitle = label;

				OnElementChanged(new ElementChangedEventArgs(element, ElementChangeType.Edited));
			}
			else
				throw new NotSupportedException();		// TODO: handle renaming of the API Project node, if possible
		}

		public override void CheckElement(XmlTreeNode node, IXPathNavigable element, bool check)
		{
			if (node == null)
				throw new ArgumentNullException("node");

			if (element == null)
				throw new ArgumentNullException("element");

			TopicNode topic = (TopicNode) node;

			topic.Topic.Expose = check;

			TopicType topicType = topic.Topic.TopicType;

			if (!checkingSiblingNodes && node != null && node.Parent != null
				&& topicType != TopicType.Container && topicType != TopicType.Conceptual
				&& topicType != TopicType.Html && topicType != TopicType.Project)

			// Cascade check value to sibling nodes with the same name (for instance, an event that doesn't 
			// have explicit add and remove accessors will have a compiler-generated field of the same name 
			// that cannot be included/exlucded independantly of the event to which it applies.)
			// In the event that two members have the same name but are unrelated, Sandcatle's apiFilter
			// configuration will still exclude or include both members together, so this dialog does the same.
			// (There actually may be some way of telling MRefBuilder the member type but that usage has 
			// not been made public at the time of writing)
			{
				checkingSiblingNodes = true;

				try
				{
					foreach (TopicNode sibling in node.Parent.Nodes)
					{
						if (sibling != node && sibling.Topic.Name.Equals(topic.Topic.Name, StringComparison.Ordinal))
							sibling.Checked = check;
					}
				}
				finally
				{
					checkingSiblingNodes = false;
				}
			}

			if (!checkingSiblingNodes)
				OnElementChanged(new ElementChangedEventArgs(element, ElementChangeType.CheckChanged));
		}

		public override bool ShouldCheckRecursive(XmlTreeNode node, IXPathNavigable element)
		{
			TopicNode topicNode = (TopicNode) node;
			Topic topic = topicNode.Topic;

			if (topic.HasMethodOverloads)
			{
				node.Parent.Checked = node.Checked;
				return false;
			}

			return true;
		}
		#endregion
	}
}
